﻿using System;
using System.Collections.Generic;
using Fuse8.DomainFramework.Domain;
using Fuse8.DomainFramework.Common;
using Fuse8.DomainFramework.Configuration.Cache;
using Fuse8.DomainFramework.Common.Locator;

namespace Fuse8.DomainFramework.CacheService
{
    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <typeparam name="TKey"></typeparam>
    public class CacheFacade<TEntity, TKey> : IEntityCacheService<TEntity, TKey>
        where TEntity : class, IEntityObject<TKey>, new()
        where TKey : IComparable<TKey>, IEquatable<TKey>
    {
        #region Fields

        private readonly IEntityCacheService<TEntity, TKey> _entityCacheService;

        private readonly ICacheDependency<TEntity, TKey> _cacheDependency;

        #endregion

	    public CacheFacade()
	    {
		    _entityCacheService = CacheServiceFactory<TEntity, TKey>.GetCacheService();
			_cacheDependency = DependencyServiceLocator.Current.IsRegistered<ICacheDependency<TEntity, TKey>>() ? DependencyServiceLocator.Current.GetInstance<ICacheDependency<TEntity, TKey>>() : null;
	    }

        #region Properties

        /// <summary>
        /// 
        /// </summary>
        public bool CacheIsDefined
        {
            get
            {
                return _entityCacheService != null;
            }
        }

        #endregion

        #region IEntityCacheService<T> Members

        /// <summary>
        /// 
        /// </summary>
        /// <param name="cacheKey"></param>
        /// <param name="entityObject"></param>
        public void AddItemToCache(string cacheKey, TEntity entityObject)
        {
            Guard.ArgumentNotEmpty(cacheKey, "cacheKey");
            Guard.ArgumentNotNull(entityObject, "entityObject");

            _entityCacheService.AddItemToCache(cacheKey, entityObject);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="cacheKey"></param>
        /// <param name="entityObjects"></param>
        public void AddListToCache(string cacheKey, IList<TEntity> entityObjects)
        {
            Guard.ArgumentNotEmpty(cacheKey, "cacheKey");
            Guard.ArgumentNotNull(entityObjects, "entityObjects");

            _entityCacheService.AddListToCache(cacheKey, entityObjects);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="cacheKey"></param>
        /// <returns></returns>
        public TEntity GetFromCache(string cacheKey)
        {
            Guard.ArgumentNotEmpty(cacheKey, "cacheKey");

            return _entityCacheService.GetFromCache(cacheKey);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="cacheKey"></param>
        /// <returns></returns>
        public IList<TEntity> GetListFromCache(string cacheKey)
        {
            Guard.ArgumentNotEmpty(cacheKey, "cacheKey");

            return _entityCacheService.GetListFromCache(cacheKey);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="cacheKey"></param>
        public void RemoveItemFromCache(string cacheKey)
        {
            Guard.ArgumentNotEmpty(cacheKey, "cacheKey");

            _entityCacheService.RemoveItemFromCache(cacheKey);
        }

        /// <summary>
        /// 
        /// </summary>
        public void ClearCache()
        {
            _entityCacheService.ClearCache();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="cacheKey"></param>
        public void AddToDependency(string cacheKey)
        {
            Guard.ArgumentNotEmpty(cacheKey, "cacheKey");

            _entityCacheService.AddToDependency(cacheKey);

            _entityCacheService.CacheOptions.AddToDependency(cacheKey);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="entityObject"></param>
        public void ClearDependency(TEntity entityObject)
        {
            if (entityObject != null)
            {
                _entityCacheService.ClearDependency(entityObject);

                if (_cacheDependency != null)
                {
                    _cacheDependency.ClearByEntityAction(entityObject);
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        public void ClearDependency(TKey id)
        {
            _entityCacheService.ClearDependency(id);

            if (_cacheDependency != null)
            {
                _cacheDependency.ClearByKeyAction(id);
            }
        }

        /// <summary>
        /// Not used
        /// </summary>
        /// <param name="successor"></param>
        public void SetSuccessor(IEntityCacheService<TEntity, TKey> successor)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 
        /// </summary>
        public IEnumerable<CacheItemView> CacheItems
        {
            get
            {
                return _entityCacheService.CacheItems;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public CacheServiceOptions CacheOptions
        {
            get
            {
                return _entityCacheService.CacheOptions;
            }
            set { }
        }

        #endregion

        #region Private methods

        /// <summary>
        /// 
        /// </summary>
        /// <param name="originalCacheKey"></param>
        /// <returns></returns>
        protected virtual string ConvertCacheKey(string originalCacheKey)
        {
            Guard.ArgumentNotEmpty(originalCacheKey, "originalCacheKey");

            return originalCacheKey.ToMD5Hash();
        }

        #endregion
    }
}
